package hu.mapro.flang.gwt.client.ui;

import hu.mapro.flang.gwt.domain.client.AutoBeans.UserPrivilege;
import hu.mapro.flang.gwt.domain.shared.Privilege;
import hu.mapro.gwtui.gxt.client.data.GxtDataUtils;
import hu.mapro.gwtui.gxt.client.fieldseditor.FieldCreationInterface;
import hu.mapro.gwtui.shared.data.ClassDataFactorySupplier;
import hu.mapro.model.Getter;
import hu.mapro.model.Setter;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.base.Objects;
import com.google.common.base.Supplier;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.editor.client.EditorDelegate;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.core.client.ToStringValueProvider;
import com.sencha.gxt.data.shared.ListStore;
import com.sencha.gxt.data.shared.SortDir;
import com.sencha.gxt.data.shared.Store.StoreSortInfo;
import com.sencha.gxt.widget.core.client.form.DualListField;
import com.sencha.gxt.widget.core.client.form.DualListField.Mode;
 
public class UserPrivilegesEditor implements hu.mapro.gwtui.gxt.client.fieldseditor.field.EditorFieldInterface<Set<UserPrivilege>> {

	Supplier<UserPrivilege> factory;
	private Setter<UserPrivilege, Object> parentSetter;
	
	private ListStore<Privilege> fromStore;
	private ListStore<Privilege> toStore;
	private DualListField<Privilege, String> dualListField;
	private EditorDelegate<Set<UserPrivilege>> delegate;


	@SuppressWarnings({ "unchecked", "rawtypes" })
	public UserPrivilegesEditor(
			//Supplier<UserPrivilege> factory, 
			Setter<UserPrivilege, ?> parentSetter) {
		//this.factory = factory;
		this.parentSetter = (Setter)parentSetter;
		fromStore = new ListStore<Privilege>(GxtDataUtils.<Privilege>enumModelKeyProvider());
		toStore = new ListStore<Privilege>(GxtDataUtils.<Privilege>enumModelKeyProvider());
		
		StoreSortInfo<Privilege> sortInfo = new StoreSortInfo<Privilege>(Ordering.<Privilege>natural(), SortDir.ASC);
		fromStore.addSortInfo(sortInfo);
		toStore.addSortInfo(sortInfo);
		
		dualListField = new DualListField<Privilege, String>(fromStore, toStore, new ToStringValueProvider<Privilege>(), new TextCell());
		dualListField.setEnableDnd(true);
		dualListField.setMode(Mode.APPEND);
		
		fromStore.replaceAll(Arrays.asList(Privilege.values()));
	}
	
	@Override
	public void setDelegate(final EditorDelegate<Set<UserPrivilege>> delegate) {
		this.delegate = delegate;
		
		dualListField.setDelegate(new EditorDelegate<List<Privilege>>() {

			@Override
			public String getPath() {
				return delegate.getPath();
			}

			@Override
			public void recordError(String message, Object value,
					Object userData) {
				delegate.recordError(message, value, userData);
			}

			@Override
			public void setDirty(boolean dirty) {
				delegate.setDirty(dirty);
			}

			@Override
			public HandlerRegistration subscribe() {
				return delegate.subscribe();
			}
		});
	}

	Map<Privilege, UserPrivilege> map = Maps.newHashMap();

	private Object baseObject;

	private Set<UserPrivilege> value;
	private Setter<Object, Set<UserPrivilege>> accessor;
	
	Set<Privilege> originalValue;
	

	private UserPrivilege getUserPrivilege(Privilege p) {
		UserPrivilege up = map.get(p);
		
		if (up==null) {
			up = factory.get();
			parentSetter.set(up, baseObject);
			up.setPrivilege(p);
			map.put(p, up);
		}
		
		return up;
	}

	@Override
	public Widget asWidget() {
		return dualListField;
	}

	@Override
	public void focus() {
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public <T, A extends Getter<T, Set<UserPrivilege>> & Setter<T, Set<UserPrivilege>>> void edit(
			A accessor, T baseObject) {
		this.baseObject = baseObject;
		this.accessor = (Setter)accessor;
		
		value = accessor.get(baseObject);
		
		//originalValue = getPrivileges(value);
		
		map.clear();
		if (value!=null) {
			for (UserPrivilege up : value) {
				map.put(up.getPrivilege(), up);
			}
		}

		toStore.replaceAll(Lists.newArrayList(map.keySet()));
		
		originalValue = Sets.newEnumSet(toStore.getAll(), Privilege.class);
		
		List<Privilege> fromValues = Lists.newArrayList(Privilege.values());
		fromValues.removeAll(toStore.getAll());
		fromStore.replaceAll(fromValues);
	}

	@Override
	public void flush() {
		if (value==null) {
			value = Sets.newHashSet();
			accessor.set(baseObject, value);
		} else {
			value.clear();
		}
		
		for (Privilege p : toStore.getAll()) {
			value.add(getUserPrivilege(p));
		}
	}

	@Override
	public void checkDirty() {
		delegate.setDirty(!Objects.equal(Sets.newEnumSet(toStore.getAll(), Privilege.class), originalValue));
	}

	@Override
	public void setContext(FieldCreationInterface ctx) {
		this.factory = ClassDataFactorySupplier.create(ctx, UserPrivilege.class);
	}

	

}
